﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DA;
using System.Text.RegularExpressions;
using Entities;

namespace BL
{
    public class OrderManager
    {
        #region Column Indexes
        //Column indexes of the Orders table.
        const int ORDERS_SUPPLIER_ID = 0;
        const int ORDERS_ORDER_NAME = 1;
        const int ORDERS_ORDER_DETAILS = 2;
        const int ORDERS_PRICE = 3;
        const int ORDERS_PAYMENT_METHOD = 4;
        const int ORDERS_BUDGET_SECTION_NUMBER = 5;
        #endregion

        public IEnumerable<ERP_Orders> GetOrders(int? UserId = null, int? OrderStatus = null)
        {
            using (dotNetivotEntities model = new dotNetivotEntities())
            {
                IQueryable<ERP_Orders> results = model.ERP_Orders.Include("ERP_Suppliers").Include("ERP_Users"); //gil .Include("ERP_ItemsInOrder").Include("ERP_OrderItems");
                if (UserId.HasValue)
                {
                    results = results.Where(x => x.UserId == UserId);
                }

                if (OrderStatus.HasValue)
                {
                    results = results.Where(x => x.OrderStatus == OrderStatus);
                }

                return results.ToList();
            }
        }

        public ERP_Orders GetOrder(int orderId)
        {
            using (dotNetivotEntities model = new dotNetivotEntities())
            {
                return model.ERP_Orders.Include("ERP_Suppliers").Include("ERP_Users").SingleOrDefault(x => x.OrderId == orderId);
            }
        }

        public bool AddOrder(ERP_Orders order)
        {
            try
            {
                using (dotNetivotEntities model = new dotNetivotEntities())
                {
                    model.ERP_Orders.AddObject(order);
                    model.SaveChanges();
                }
            }
            catch
            {
                return false;
            }
            return true;

        }

        public bool EditOrder(int orderId, ERP_Orders order)
        {
            try
            {
                using (dotNetivotEntities model = new dotNetivotEntities())
                {
                    ERP_Orders orderToUpdate = model.ERP_Orders.SingleOrDefault(x => x.OrderId == orderId);
                    orderToUpdate.SupplierId = order.SupplierId;
                    orderToUpdate.OrderDetails = order.OrderDetails;
                    orderToUpdate.OrderReason = order.OrderReason;
                    orderToUpdate.Price = order.Price;
                    orderToUpdate.BudgetSectionNumber = order.BudgetSectionNumber;
                    orderToUpdate.PaymentMethod = order.PaymentMethod;
                    orderToUpdate.OrderStatus = order.OrderStatus;

                    model.SaveChanges();
                    model.AcceptAllChanges();
                }
            }
            catch
            {
                return false;
            }

            return true;
        }

        public bool EditOrderStatus(int orderId, int orderStatus, string managerNotes)
        {
            try
            {
                using (dotNetivotEntities model = new dotNetivotEntities())
                {
                    ERP_Orders orderToUpdate = model.ERP_Orders.SingleOrDefault(x => x.OrderId == orderId);
                    orderToUpdate.OrderStatus = orderStatus;
                    orderToUpdate.ManagerNotes = managerNotes;

                    model.SaveChanges();
                    model.AcceptAllChanges();
                }
            }
            catch
            {
                return false;
            }

            return true;
        }

        public List<CsvError> ImportOrdersFromCSV(string fileString)
        {
            List<CsvError> ErrorList = new List<CsvError>();
            List<ERP_Orders> OrderList = new List<ERP_Orders>();

            string[] Lines = Regex.Split(fileString, Environment.NewLine);

            for (int lineIndex = 1; lineIndex < Lines.Count(); lineIndex++)
            {
                string[] Columns = Regex.Split(Lines[lineIndex], ",");

                List<CsvError> lineErrors = ValidateOrderValues(Columns, lineIndex);

                if (lineErrors.Count() == 0)
                {
                    OrderList.Add(
                        new ERP_Orders()
                        {
                            UserId = 1,
                            SupplierId = Columns[ORDERS_SUPPLIER_ID].ToInt().Value,
                            OrderDetails = Columns[ORDERS_ORDER_DETAILS],
                            Price = Columns[ORDERS_PRICE].ToDecimal().Value,
                            PaymentMethod = Columns[ORDERS_PAYMENT_METHOD].ToInt().Value.ToString(),
                            BudgetSectionNumber = Columns[ORDERS_BUDGET_SECTION_NUMBER].ToInt(),
                            CreationDate = DateTime.Now
                        }
                        );
                }
                else
                {
                    ErrorList.AddRange(lineErrors);
                }
            }

            using (dotNetivotEntities model = new dotNetivotEntities())
            {
                foreach (ERP_Orders order in OrderList)
                {
                    model.ERP_Orders.AddObject(order);
                }
                model.SaveChanges();
            }

            return ErrorList;
        }

        private List<CsvError> ValidateOrderValues(string[] columns, int line)
        {
            List<CsvError> errors = new List<CsvError>();

            columns[ORDERS_SUPPLIER_ID] = columns[ORDERS_SUPPLIER_ID].Trim();
            columns[ORDERS_ORDER_NAME] = columns[ORDERS_ORDER_NAME].Trim();
            columns[ORDERS_ORDER_DETAILS] = columns[ORDERS_ORDER_DETAILS].Trim();
            columns[ORDERS_PRICE] = columns[ORDERS_PRICE].Trim();
            columns[ORDERS_PAYMENT_METHOD] = columns[ORDERS_PAYMENT_METHOD].Trim();
            columns[ORDERS_BUDGET_SECTION_NUMBER] = columns[ORDERS_BUDGET_SECTION_NUMBER].Trim();

            if (!columns[ORDERS_SUPPLIER_ID].IsInt())
            {
                errors.Add(
                    new CsvError()
                    {
                        Line = line,
                        Description = "The supplier id is not valid."
                    }
                    );
            }
            else
            {
                bool supplierIdExist;
                using (dotNetivotEntities model = new dotNetivotEntities())
                {
                    int suppliersId = columns[ORDERS_SUPPLIER_ID].ToInt().Value;
                    supplierIdExist = model.ERP_Suppliers.Any(x => x.SupplierId == suppliersId);
                }

                if (!supplierIdExist)
                {
                    errors.Add(
                        new CsvError()
                        {
                            Line = line,
                            Description = "The supplier id does not exist in the database."
                        }
                        );
                }
            }

            if (!columns[ORDERS_PRICE].IsNumber())
            {
                errors.Add(
                    new CsvError()
                    {
                        Line = line,
                        Description = "The price is not a valid number."
                    }
                    );
            }

            if (columns[ORDERS_ORDER_NAME].Length > 50)
            {
                errors.Add(
                    new CsvError()
                    {
                        Line = line,
                        Description = "The order name field is too long."
                    }
                    );
            }

            if (columns[ORDERS_ORDER_DETAILS].Length > 50)
            {
                errors.Add(
                    new CsvError()
                    {
                        Line = line,
                        Description = "The order details field is too long."
                    }
                    );
            }

            if (!columns[ORDERS_PAYMENT_METHOD].IsInt())
            {
                errors.Add(
                    new CsvError()
                    {
                        Line = line,
                        Description = "The payment method is not valid."
                    }
                    );
            }

            if (!columns[ORDERS_BUDGET_SECTION_NUMBER].IsInt() && columns[ORDERS_BUDGET_SECTION_NUMBER] != "")
            {
                errors.Add(
                    new CsvError()
                    {
                        Line = line,
                        Description = "The budget section number is not valid."
                    }
                    );
            }

            return errors;
        }

        public decimal GetOrderPrice(int orderId)
        {
            using (dotNetivotEntities model = new dotNetivotEntities())
            {
                if (model.ERP_ItemsInOrder.Any(x => x.OrderId == orderId))
                {
                    return model.ERP_ItemsInOrder.Where(x => x.OrderId == orderId).Sum(x => x.Price);
                }
                else
                {
                    return 0m;
                }
            }
        }

        public bool DeleteOrder(int orderId)
        {

            try
            {
                using (dotNetivotEntities model = new dotNetivotEntities())
                {
                    IEnumerable<ERP_ItemsInOrder> itemsToDelete = model.ERP_ItemsInOrder.Where(x => x.OrderId == orderId);
                    foreach (ERP_ItemsInOrder item in itemsToDelete)
                    {
                        model.ERP_ItemsInOrder.DeleteObject(item);
                    }
                    model.ERP_Orders.DeleteObject(model.ERP_Orders.SingleOrDefault(x => x.OrderId == orderId));
                    model.SaveChanges();
                }
            }
            catch
            {
                return false;
            }
            return true;
        }
    }
}
